public class scriptController {

    public List<SelectOption> getScripts() {
        List<SelectOption> optionList = new List<SelectOption>();
        for (Chatter_Script__c cs : [ Select id,name from Chatter_Script__c ORDER By Name ASC]) {
                optionList.add(new SelectOption(cs.id,cs.name));
        }
        return optionList;
    }
    
   
    
    public String scriptName { get; set;}
    public String reset { get; set; }
    public Integer postCount { get; set; }
    public Integer commentCount { get; set; }
    public Boolean countsDone = false;
      
    String actions = '';
        String scriptOption;
        Decimal count = 0;
        public Decimal increment = 0;
        Integer recordCount = 0;
        String result = '';
        String userId = UserInfo.getUserId().substring(0,15);
        Chatter_Script__c script ;
        List<Chatter_Post__c> postUpdates = new List<Chatter_Post__c>();
        Set<Chatter_Comment__c> commentUpdates = new Set<Chatter_Comment__c>(); // use this to store all comment updates
        List<Chatter_Register__c> actionTable = new List<Chatter_Register__c>();
        List<NewsFeed> myfeed = new List<NewsFeed>();

        // get name of Script from VF page paramter, and pull primary actor
        
        //String scriptName = ApexPages.currentPage().getParameters().get('s');
          
        public PageReference incrementCounter() {
        // get script details and handle counter value
        if (scriptName != '' && scriptName != null) {
            system.debug('scriptName = '+scriptName);
            try {
                script = [Select Id, Name, Counter__c, Focus_Actor__c from Chatter_Script__c where Id =:scriptName LIMIT 1 ]; 
            } catch (exception e) {
                System.debug('Error at query for script data:'+e);
            }
            scriptName = script.Name;
            script.Counter__c = count;
            update script;
                        
            System.debug('****************** Count variable is currently '+String.valueOf(count));
            System.debug('****************** Script variable is currently '+scriptName);
            System.debug('****************** userId is '+UserInfo.getUserId());
        
        // now have count variable, check for appropriate Posts based on timing/cycle count
        
            
            for (Chatter_Post__c post : [Select Id, Name, Deployed__c, Post_type__c, Link_URL__c, Cycle__c, Actor__c, Script__r.Name, Post_Parent_record_Id__c from Chatter_Post__c WHERE Target_Cycle__c =:count AND Script__r.Name =:scriptName AND Deployed__c = FALSE ]) {
                    System.debug('******************* Post has been found and will be added ***************'+ post);
                    
                    // add Posts and update Post records
                    addPost( post.Actor__c, post.Post_Parent_record_Id__c, post.Name, post );
                    post.Deployed__c = TRUE;
                    update post;
            } 
            
        // now check for Posts based on SOQL
        
            postUpdates.clear();
            for (Chatter_Post__c post : [Select Id, Actor__c, Deployed__c, Cycle__c, Post_type__c, Link_URL__c, Name, Target_Condition__c, Post_Parent_record_Id__c from Chatter_Post__c WHERE Target_Condition__c != NULL AND Deployed__c = FALSE ]) {
                System.debug('********** trying post dynamic apex:'+post.Target_Condition__c);
                // run dynamic apex and see if condition met
                result = '';
                try {
                    result = String.valueOf(Database.query(post.Target_Condition__c )[0].Id);
                    } 
                catch (exception e) {
                    System.debug('Error occured while querying SOQL on post entries:'+ e);
                    }
                    
                if (result != '') {
                    // add Posts and update Post records
                    addPost( post.Actor__c,post.Post_Parent_record_Id__c , post.Name, post );
                    post.Deployed__c = TRUE;
                    update post;
                }
            } 
            
        // now we check for Comments to be added based on cycle count i.e. absolute timing
            
            for (Chatter_Comment__c comment : [ Select Id, Absolute_Cycles__c, Actor__c, Script_Name__c, Name, Post__r.Post_Id__c, Deployed__c from Chatter_Comment__c WHERE
                                                                        Absolute_Cycles__c =: count AND
                                                                        Post__r.Deployed__c = TRUE AND
                                                                        Deployed__c = FALSE AND
                                                                        Script_Name__c =:scriptName]) {
                // add Comments
                addComment( comment.Actor__c, comment.Post__r.Post_Id__c, comment.Name, comment);
                comment.Deployed__c = TRUE;
                update comment;
            }
         
        // now check for Comments that are spawned when Posts contain certain text
            
            myfeed = [SELECT Id, Type, 
                                                        CreatedById, CreatedBy.FirstName, CreatedBy.LastName, CreatedDate,
                                                        ParentId, Parent.Name, 
                                                        FeedPostId, FeedPost.Body, FeedPost.Title, FeedPost.CreatedById
                                                        FROM NewsFeed WHERE FeedPost.Body != ''];
                                                        
            For (NewsFeed m : myfeed) 
            System.debug('******************************* myfeed = '+m.FeedPost.Body +' and FeedPostId = '+m.FeedPostId + 'and Title is :'+m.FeedPost.Title );
                                                    
            for (Chatter_Comment__c comment : [ Select Name, Absolute_Cycles__c, Deployed__c, Post__c, Post__r.Cycle__c, Post__r.Name, Post__r.Post_Id__c from Chatter_Comment__c WHERE
                                                                        Post__c != null AND
                                                                        Deployed__c = FALSE AND
                                                                        Script_Name__c =:scriptName ]) {
                
                // cycle through list and check for Posts containing said text
                
                for ( NewsFeed m : myfeed) {
                    if (  comment.Post__r.Name == m.FeedPost.Body) {
                    System.debug('&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& we have matched a post '+m.FeedPost.Body);
                        if (comment.Absolute_Cycles__c == count) addComment( comment.Actor__c , m.Id, comment.Name, comment );
                        Chatter_Post__c cp = new Chatter_Post__c (Id = comment.Post__r.Id, Post_Id__c = m.Id, Deployed__c = TRUE );
                        if (comment.Post__r.Cycle__c == null) cp.Cycle__c = count;
                        update cp;
                    }
                } 
            }
                
                                                                    
             
        
       
        
                                                                       
        
    count = count + increment;  
        }
    return null;
    
        }
                    
        public Decimal getCount() {
                return count;
        }
        
        public String getActions() {
                return actions;
        }
        
        public List<Chatter_Register__c> getActionTable() {
                return actionTable;
        }
                
        //
        // add comment to post
        //
        public void addComment ( Id ActorId, Id parentId, String Name, Chatter_Comment__c comment) {
                
                // build out an email with required parameters to build comment upon receipt and send to email2sforce service to achieve user context.
                List<User> uu = new List<User>([Select Id,Name, Email, Email_to_Salesforce_address__c from User WHERE Id =:ActorId ]);
                // build out an email with required parameters to build post upon receipt and send to email2sforce service to achieve user context.
                Messaging.SingleEmailMessage mailComment = new Messaging.SingleEmailMessage();
                String[] toAddresses = new String[]{} ;
                toAddresses.add(uu[0].Email_to_Salesforce_address__c );
                mailComment.setToAddresses(toAddresses);
                system.debug('----------------- mail.setToAddresses =:'+toAddresses);
                mailComment.setReplyTo(uu[0].Email);
                mailComment.setSenderDisplayName(uu[0].Name);
                mailComment.setSubject('New Comment');
                mailComment.setBccSender(false);
                mailComment.setUseSignature(false);
                String textContent;
                
                // add body containing required information
                textContent +='<parentId:' +parentId+'>';
                textContent += '<CommentBody:' + Name + '>';
                
                
                system.debug('body of email being sent is ----> '+textContent);
                mailComment.setPlainTextBody(textContent);
                Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mailComment }); 
                
                comment.Deployed__c = TRUE;
                update comment;
                //commentUpdates.add(comment); // bulk update later
                addToRegister( 'comment', 'Comment added --> '+Name ,parentId );
                refreshActionTable();
                commentCount = commentCount -1;
                if (postCount == 0 && commentCount == 0) startStop(); // stop chattering if nothing left to do.
                return;
                
        }
           
        public void addToRegister ( String typePost, String newRecord , String pId) {
        // add new post or comment to register
        Chatter_Register__c regEntry = new Chatter_Register__c ( Name = 'New Record' , Type__c = typePost, Action__c = newRecord , ParentId__c = pId);
        insert regEntry;
        return;
        }
            
            
        //
        // create a new post record and add minimum info
        //    
        public void addPost(Id ActorId, String parentId, String Name, Chatter_Post__c post) {
                
                List<User> u = new List<User>([Select Id,Name, Email, Email_to_Salesforce_address__c from User WHERE Id =:ActorId ]);
                // build out an email with required parameters to build post upon receipt and send to email2sforce service to achieve user context.
                Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
                String[] toAddresses = new String[]{} ;
                toAddresses.add(u[0].Email_to_Salesforce_address__c );
                mail.setToAddresses(toAddresses);
                system.debug('----------------- mail.setToAddresses =:'+toAddresses);
                mail.setReplyTo(u[0].Email);
                mail.setSenderDisplayName(u[0].Name);
                mail.setSubject('New Post');
                mail.setBccSender(false);
                mail.setUseSignature(false);
                String textContent;
                
                // add body containing required information
                textContent +='<ActorId:'+ActorId+'>';
                textContent +='<parentId:' +parentId+'>';
                textContent +='<post.Post_type__c:' +post.Post_type__c+'>';
                textContent +='<post.Link_URL__c:' + post.Link_URL__c+'>';
                textContent +='<post.Name:'+post.Name+'>';
                textContent +='<post.Id:'+post.Id+'>';
                textContent +='<post.Cycle__c:'+post.Cycle__c+'>';
                
                system.debug('body of email being sent is ----> '+textContent);
                mail.setPlainTextBody(textContent);
                Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail }); 
                
                List<Newsfeed> myfeed = [SELECT Id, Type,CreatedById, CreatedBy.FirstName, CreatedBy.LastName, CreatedDate, ParentId, Parent.Name, FeedPostId, FeedPost.Body, FeedPost.Title, FeedPost.CreatedById, (SELECT Id, FieldName, OldValue, NewValue FROM FeedTrackedChanges ORDER BY Id DESC), (SELECT Id, CommentBody, CreatedDate,CreatedById, CreatedBy.FirstName, CreatedBy.LastName FROM FeedComments ORDER BY CreatedDate, ID DESC LIMIT 10) FROM NewsFeed ORDER BY CreatedDate DESC LIMIT 1];
                        post.Post_Id__c = myfeed.get(0).Id;
                        if (post.Cycle__c == null) post.Cycle__c = count;
                        post.Deployed__c = TRUE;
                        postUpdates.add(post); 
                        addToRegister( 'post' , 'Post added --> '+Name, parentId);
                        refreshActionTable();
                postCount = postCount - 1;
                if (postCount == 0 && commentCount == 0) startStop(); // stop chattering if nothing left to do.
                return;
        }
        
        //
        // this method gets things setup at beginning of script execution
        //
        public PageReference resetCounter() {
                // this is used on page load to ensure non primary user sees counter set to zero.
                increment = 0;
                Chatter_Script__c script = [Select Id, Name, Counter__c, Focus_Actor__c from Chatter_Script__c where Name =:scriptName LIMIT 1 ];
                if (script.Counter__c != 0) {
                        script.Counter__c = 0;
                        update script;
                }
                
                // if is primary user updating the record, and counter field = 0 then a script is executing and we need to ensure all associated post
                // and comment data is ready for use.
                List<Chatter_Post__c> posts = new List<Chatter_Post__c>();

                        for ( Chatter_Post__c p : [Select Id, Post_Id__c, Cycle__c, Deployed__c from Chatter_Post__c ]) {
                                p.Deployed__c = FALSE;
                                p.Post_Id__c = null;
                                p.Cycle__c = null;
                                posts.add(p);
                        }

                        if (posts.size()>0) update posts;
                        
                        // Do the same for Comments
                        
                        List<Chatter_Comment__c>  comments = new List<Chatter_Comment__c>();
                        for (Chatter_Comment__c c : [ Select Id, Deployed__c from Chatter_Comment__c ]) {
                                c.Deployed__c = FALSE;
                                comments.add(c);
                        }
                        if (comments.size() > 0) update comments;
                
                return null;
        }
        
        //
        // clear out all the post and comment records as stored in the register cObj.
        // 
        public PageReference reset() {
        increment = 0;
        count = 0;
        postCount = 0;
        commentCount = 0;
        actions = '';
        countsDone = false;
        List<Chatter_Register__c> reg = new List<Chatter_Register__c>([ Select Id from Chatter_Register__c]);
        if (reg.size() > 0) {
          delete reg;
          refreshActionTable();
        }
        
        List<Chatter_Post__c> posts = new List<Chatter_Post__c>([ Select Id, Post_Id__c, Deployed__c from Chatter_Post__c ]);
        List<Id> postsForDeletion = new List<Id>();
        for (Chatter_Post__c p : posts) {
          if (p.Deployed__c == TRUE) postsForDeletion.add(p.Post_Id__c);
          p.Deployed__c = FALSE;
        }
        update posts;
        
        // try to delete out the posts we created
        List<FeedPost> fp = new List<FeedPost>();
        for (NewsFeed p : [Select Id,FeedPostId from NewsFeed where Id in:postsForDeletion]) { fp.add(new FeedPost(Id = p.FeedPostId)); }
        if (fp.size()>0) delete fp;
        
        List<Chatter_Comment__c> comments = new List<Chatter_Comment__c>([ Select Id, Deployed__c from Chatter_Comment__c ]);
        for (Chatter_Comment__c c : comments) c.Deployed__c = FALSE;
        update comments;
        
        return null;
        }
        
        
        // 
        // toggle to start/stop the script counter 
        //
        public PageReference startStop() {
   
                if (increment == 0) { 
                        increment = 1;
                        // TODO - calculate counts here, and then flick countsDone = true
                        system.debug('scriptName at count query is '+scriptName);
                        List<Chatter_Post__c> pc = new List<Chatter_Post__c>([Select Id from Chatter_Post__c where Script__r.Id =:scriptName]);
                        postCount = pc.size();
                        commentCount = [Select Count() from  Chatter_Comment__c where Post__c in:pc];
                        countsDone = true;
                } else {
                        increment = 0;
                }
                return null;
        }
        
        
        //
        // update the actionTable List to reflect actions executed to date
        //
        public PageReference refreshActionTable() {
        actionTable = [ Select Id, Type__c, Name, ParentId__c, Action__c from Chatter_Register__c ORDER BY CreatedDate DESC ];
        return null;
        }
        
        //
        // get List of scripts for use in scripts picklist
        //
        public List<SelectOption> getscriptOptions () {
                List<SelectOption> scriptOptions = new List<SelectOption>();
                for (Chatter_Script__c cs : [select id,Name from Chatter_Script__c ORDER by Name]) {
                        scriptOptions.add(new SelectOption(cs.id,cs.Name));
                }
                return scriptOptions;
        }
        
        public String getscriptOption() { return this.scriptOption; }
        
        public void setscriptOption(String s) { this.scriptName = s; }
        
        public Boolean getIncrement() { 
                if ( this.increment == 1 ) { return TRUE; } else { return FALSE; }
        }
}